/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.ryan.ohos.extension.widget.toolbar;

import com.ryan.ohos.extension.*;
import com.ryan.ohos.extension.event.DispatchHelper;
import com.ryan.ohos.extension.event.impl.ViewGroupHelper;
import com.ryan.ohos.extension.event.interfaces.ViewGroup;
import com.ryan.ohos.extension.nested.component.AppBarLayout;
import com.ryan.ohos.extension.nested.component.coordinatorlayout.CoordinatorLayout;
import com.ryan.ohos.extension.util.WindowUtil;
import ohos.aafwk.ability.Ability;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.VectorElement;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.WrongTypeException;
import ohos.global.resource.solidxml.Pattern;
import ohos.global.resource.solidxml.TypedAttribute;
import ohos.multimodalinput.event.TouchEvent;

import javax.annotation.processing.SupportedSourceVersion;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static com.ryan.ohos.extension.EstimateHelper.getChildMeasureSpec;

public class Toolbar extends ComponentContainer implements
        Component.EstimateSizeListener, ComponentContainer.ArrangeListener,
        Component.TouchEventListener, ViewGroup {

    private static final String TAG = "Toolbar";

    private Component mStatusBarView;
    //    private ActionMenuView mMenuView;
    private Text mTitleTextView;
    private Text mSubtitleTextView;
    private DirectionalLayout mNavButtonLayout;
    private Image mNavButtonView; // ImageButton
    private Image mLogoView;

    private Element mCollapseIcon;
    //    private CharSequence mCollapseDescription;
    Image mCollapseButtonView; // ImageButton
    Component mExpandedActionView;

//    /** Context against which to inflate popup menus. */
//    private Context mPopupContext;

//    /**
//     * Theme resource against which to inflate popup menus.
//     */
//    private int mPopupTheme;

    private int mTitleTextAppearance;
    private int mSubtitleTextAppearance;

    int mButtonGravity;

    private int mNavigationIconWidth;
    private int mMaxButtonHeight;

    private int mStatusBarHeight;

    private int mTitleMarginStart;
    private int mTitleMarginEnd;
    private int mTitleMarginTop;
    private int mTitleMarginBottom;

    private RtlSpacingHelper mContentInsets;
    private int mContentInsetStartWithNavigation;
    private int mContentInsetEndWithActions;

    private int mGravity = Gravity.START | Gravity.CENTER_VERTICAL;

    private String mTitleText;
    private String mSubtitleText;

    private int mTitleTextColor;
    private int mSubtitleTextColor;

    private int mTitleTextSize;
    private int mSubtitleTextSize;

    private boolean mEatingTouch;
    private boolean mEatingHover;

    // Clear me after use.
    private final ArrayList<Component> mTempViews = new ArrayList<>();

    // Used to hold views that will be removed while we have an expanded action view.
    private final ArrayList<Component> mHiddenViews = new ArrayList<>();

    private final int[] mTempMargins = new int[2];

//    OnMenuItemClickListener mOnMenuItemClickListener;

//    private final ActionMenuView.OnMenuItemClickListener mMenuViewItemClickListener =
//            new ActionMenuView.OnMenuItemClickListener() {
//                @Override
//                public boolean onMenuItemClick(MenuItem item) {
//                    if (mOnMenuItemClickListener != null) {
//                        return mOnMenuItemClickListener.onMenuItemClick(item);
//                    }
//                    return false;
//                }
//            };

//    private ToolbarWidgetWrapper mWrapper;
//    private ActionMenuPresenter mOuterActionMenuPresenter;
//    private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
//    private MenuPresenter.Callback mActionMenuPresenterCallback;
//    private MenuBuilder.Callback mMenuBuilderCallback;

    private boolean mCollapsible;
    private final ViewGroupHelper mViewGroupHelper;

//    private final Runnable mShowOverflowMenuRunnable = new Runnable() {
//        @Override public void run() {
//            showOverflowMenu();
//        }
//    };

    public Toolbar(Context context) {
        this(context, null);
    }

    public Toolbar(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public Toolbar(Context context, AttrSet attrs, String styleName) {
        super(context, attrs, styleName);

        setTouchEventListener(this);
        setEstimateSizeListener(this);
        setArrangeListener(this);

        mViewGroupHelper = new ViewGroupHelper(this);
        try {
            Pattern pattern = context.getResourceManager().getElement(ResourceTable.Pattern_toolBar).getPattern();

            mStatusBarHeight = attrs.getAttr("statusBarHeight").map(Attr::getDimensionValue)
                    .orElse(WindowUtil.getStatusBarHeightInPixels(getContext()));

            Element statusBarBackground = attrs.getAttr("statusBarBackground").map(Attr::getElement).orElse(null);
            if (statusBarBackground == null) {
//                ShapeElement se = new ShapeElement();
//                se.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor("#000000")));
                statusBarBackground = new ShapeElement();
            }
            setStatusBarBackground(statusBarBackground);

//        mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
//        mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
            mGravity = Gravity.convert(attrs.getAttr("gravity").map(Attr::getStringValue).orElse(""));
            mButtonGravity = Gravity.convert(attrs.getAttr("buttonGravity").map(Attr::getStringValue)
                    .orElse(pattern.getPatternHash().get("buttonGravity").getStringValue()));

            final int minHeight = attrs.getAttr("min_height").map(Attr::getDimensionValue)
                    .orElse((int) pattern.getPatternHash().get("min_height").getFloatValue());
            if (minHeight > 0) {
                setMinHeight(minHeight);
            }

            // First read the correct attribute
            int titleMargin = attrs.getAttr("titleMargin").map(Attr::getDimensionValue)
                    .orElse((int) pattern.getPatternHash().get("titleMargin").getFloatValue());
            mTitleMarginStart = mTitleMarginEnd = mTitleMarginTop = mTitleMarginBottom = titleMargin;

            final int marginStart = attrs.getAttr("titleMarginStart").map(Attr::getDimensionValue).orElse(-1);
            if (marginStart >= 0) {
                mTitleMarginStart = marginStart;
            }

            final int marginEnd = attrs.getAttr("titleMarginEnd").map(Attr::getDimensionValue).orElse(-1);
            if (marginEnd >= 0) {
                mTitleMarginEnd = marginEnd;
            }

            final int marginTop = attrs.getAttr("titleMarginTop").map(Attr::getDimensionValue).orElse(-1);
            if (marginTop >= 0) {
                mTitleMarginTop = marginTop;
            }

            final int marginBottom = attrs.getAttr("titleMarginBottom").map(Attr::getDimensionValue).orElse(-1);
            if (marginBottom >= 0) {
                mTitleMarginBottom = marginBottom;
            }

            mNavigationIconWidth = attrs.getAttr("navigationIconWidth").map(Attr::getDimensionValue)
                    .orElse((int) pattern.getPatternHash().get("navigationIconWidth").getFloatValue());
            mMaxButtonHeight = attrs.getAttr("maxButtonHeight").map(Attr::getDimensionValue)
                    .orElse((int) pattern.getPatternHash().get("maxButtonHeight").getFloatValue());

            final int contentInsetStart =
                    attrs.getAttr("contentInsetStart").map(Attr::getDimensionValue)
                            .orElse((int) pattern.getPatternHash().get("contentInsetStart").getFloatValue());
            final int contentInsetEnd =
                    attrs.getAttr("contentInsetEnd").map(Attr::getDimensionValue)
                            .orElse(RtlSpacingHelper.UNDEFINED);
            final int contentInsetLeft =
                    attrs.getAttr("contentInsetLeft").map(Attr::getDimensionValue)
                            .orElse(RtlSpacingHelper.UNDEFINED);
            final int contentInsetRight =
                    attrs.getAttr("contentInsetRight").map(Attr::getDimensionValue)
                            .orElse(RtlSpacingHelper.UNDEFINED);

            ensureContentInsets();
            mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);

            if (contentInsetStart != RtlSpacingHelper.UNDEFINED ||
                    contentInsetEnd != RtlSpacingHelper.UNDEFINED) {
                mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
            }

            mContentInsetStartWithNavigation = attrs.getAttr("contentInsetStartWithNavigation").map(Attr::getDimensionValue)
                    .orElse((int) pattern.getPatternHash().get("contentInsetStartWithNavigation").getFloatValue());
            mContentInsetEndWithActions = attrs.getAttr("contentInsetEndWithActions").map(Attr::getDimensionValue)
                    .orElse(RtlSpacingHelper.UNDEFINED);

            mCollapseIcon = attrs.getAttr("collapseIcon").map(Attr::getElement).orElse(null);
//        mCollapseDescription = a.getText(R.styleable.Toolbar_collapseContentDescription);

            final String title = attrs.getAttr("title").map(Attr::getStringValue).orElse("");
            if (!TextUtils.isEmpty(title)) {
                setTitle(title);
            }

            if (!TextUtils.isEmpty(title)) {
                setTitle(title);
            }

            final String subtitle = attrs.getAttr("subtitle").map(Attr::getStringValue).orElse("");
            if (!TextUtils.isEmpty(subtitle)) {
                setSubtitle(subtitle);
            }

            // Set the default context, since setPopupTheme() may be a no-op.
//        mPopupContext = getContext();
//        setPopupTheme(a.getResourceId(R.styleable.Toolbar_popupTheme, 0));

            Element navIcon = attrs.getAttr("navigationIcon").map(Attr::getElement).orElse(null);
            boolean hideNavIcon = attrs.getAttr("hideNavigationIcon").map(Attr::getBoolValue).orElse(false);
            if (navIcon == null) {
                if (!hideNavIcon) {
                    TypedAttribute ta = pattern.getPatternHash().get("navigationIcon");
                    setNavigationIcon(new VectorElement(context, ta.getResId()));
                }
            } else {
                setNavigationIcon(navIcon);
            }
//        final CharSequence navDesc = a.getText(R.styleable.Toolbar_navigationContentDescription);
//        if (!TextUtils.isEmpty(navDesc)) {
//            setNavigationContentDescription(navDesc);
//        }

            final Element logo = attrs.getAttr("logo").map(Attr::getElement).orElse(null);
            if (logo != null) {
                setLogo(logo);
            }

//        final CharSequence logoDesc = a.getText(R.styleable.Toolbar_logoDescription);
//        if (!TextUtils.isEmpty(logoDesc)) {
//            setLogoDescription(logoDesc);
//        }

            Optional<Attr> titleTextColor = attrs.getAttr("titleTextColor");
            titleTextColor.ifPresent(attr -> setTitleTextColor(attr.getColorValue().getValue()));
            if (!titleTextColor.isPresent()) {
                setTitleTextColor(pattern.getPatternHash().get("titleTextColor").getColorValue());
            }

            Optional<Attr> subtitleTextColor = attrs.getAttr("subtitleTextColor");
            subtitleTextColor.ifPresent(attr -> setSubtitleTextColor(attr.getColorValue().getValue()));
            if (!subtitleTextColor.isPresent()) {
                setSubtitleTextColor(pattern.getPatternHash().get("subtitleTextColor").getColorValue());
            }

            Optional<Attr> titleTextSize = attrs.getAttr("titleTextSize");
            titleTextSize.ifPresent(attr -> setTitleTextSize(attr.getDimensionValue()));
            if (!titleTextSize.isPresent()) {
                setTitleTextSize((int) pattern.getPatternHash().get("titleTextSize").getFloatValue());
            }

            Optional<Attr> subtitleTextSize = attrs.getAttr("subtitleTextSize");
            subtitleTextSize.ifPresent(attr -> setSubtitleTextSize(attr.getDimensionValue()));
            if (!subtitleTextSize.isPresent()) {
                setSubtitleTextSize((int) pattern.getPatternHash().get("subtitleTextSize").getFloatValue());
            }

        } catch (IOException | NotExistException | WrongTypeException e) {
            e.printStackTrace();
        }
    }

    @Override
    public int getMinHeight() {
        return super.getMinHeight() + mStatusBarHeight;
    }

    //    /**
//     * Specifies the theme to use when inflating popup menus. By default, uses
//     * the same theme as the toolbar itself.
//     *
//     * @param resId theme used to inflate popup menus
//     * @see #getPopupTheme()
//     */
//    public void setPopupTheme(@StyleRes int resId) {
//        if (mPopupTheme != resId) {
//            mPopupTheme = resId;
//            if (resId == 0) {
//                mPopupContext = getContext();
//            } else {
//                mPopupContext = new ContextThemeWrapper(getContext(), resId);
//            }
//        }
//    }

//    /**
//     * @return resource identifier of the theme used to inflate popup menus, or
//     *         0 if menus are inflated against the toolbar theme
//     * @see #setPopupTheme(int)
//     */
//    public int getPopupTheme() {
//        return mPopupTheme;
//    }

    /**
     * Set the height of the fake status bar.
     *
     * @param height Height to set
     */
    public void setStatusBarHeight(int height) {
        mStatusBarHeight = height;
        postLayout();
    }

    /**
     * the height of fake status bar
     *
     * @return the height of fake status bar
     */
    public int getStatusBarHeight() {
        return mStatusBarHeight;
    }

    /**
     * Set the background of the fake status bar.
     *
     * @param bg Drawable to set, may be null to clear the background
     */
    public void setStatusBarBackground(Element bg) {
        ensureStatusBarView();
        if (!isChildOrHidden(mStatusBarView)) {
            addSystemView(mStatusBarView, true);
        }
        if (mStatusBarView != null) {
            mStatusBarView.setBackground(bg);
        }
    }

    /**
     * Sets the title margin.
     *
     * @param start  the starting title margin in pixels
     * @param top    the top title margin in pixels
     * @param end    the ending title margin in pixels
     * @param bottom the bottom title margin in pixels
     */
    public void setTitleMargin(int start, int top, int end, int bottom) {
        mTitleMarginStart = start;
        mTitleMarginTop = top;
        mTitleMarginEnd = end;
        mTitleMarginBottom = bottom;

        postLayout();
    }

    /**
     * the starting title margin in pixels
     *
     * @return the starting title margin in pixels
     */
    public int getTitleMarginStart() {
        return mTitleMarginStart;
    }

    /**
     * Sets the starting title margin in pixels.
     *
     * @param margin the starting title margin in pixels
     */
    public void setTitleMarginStart(int margin) {
        mTitleMarginStart = margin;

        postLayout();
    }

    /**
     * @return the top title margin in pixels
     */
    public int getTitleMarginTop() {
        return mTitleMarginTop;
    }

    /**
     * Sets the top title margin in pixels.
     *
     * @param margin the top title margin in pixels
     */
    public void setTitleMarginTop(int margin) {
        mTitleMarginTop = margin;

        postLayout();
    }

    /**
     * @return the ending title margin in pixels
     */
    public int getTitleMarginEnd() {
        return mTitleMarginEnd;
    }

    /**
     * Sets the ending title margin in pixels.
     *
     * @param margin the ending title margin in pixels
     */
    public void setTitleMarginEnd(int margin) {
        mTitleMarginEnd = margin;

        postLayout();
    }

    /**
     * @return the bottom title margin in pixels
     */
    public int getTitleMarginBottom() {
        return mTitleMarginBottom;
    }

    /**
     * Sets the bottom title margin in pixels.
     *
     * @param margin the bottom title margin in pixels
     */
    public void setTitleMarginBottom(int margin) {
        mTitleMarginBottom = margin;
        postLayout();
    }

    public void onRtlPropertiesChanged(LayoutDirection layoutDirection) {
//        if (Build.VERSION.SDK_INT >= 17) {
//            super.onRtlPropertiesChanged(layoutDirection);
//        }

        ensureContentInsets();
        mContentInsets.setDirection(layoutDirection == LayoutDirection.RTL);
    }

//    /**
//     * Set a logo drawable from a resource id.
//     *
//     * <p>This drawable should generally take the place of title text. The logo cannot be
//     * clicked. Apps using a logo should also supply a description using
//     * {@link #setLogoDescription(int)}.</p>
//     *
//     * @param resId ID of a drawable resource
//     */
//    public void setLogo(int resId) {
//        setLogo(AppCompatResources.getDrawable(getContext(), resId));
//    }

//    /** @hide */
//    public boolean canShowOverflowMenu() {
//        return getVisibility() == VISIBLE && mMenuView != null && mMenuView.isOverflowReserved();
//    }

//    /**
//     * Check whether the overflow menu is currently showing. This may not reflect
//     * a pending show operation in progress.
//     *
//     * @return true if the overflow menu is currently showing
//     */
//    public boolean isOverflowMenuShowing() {
//        return mMenuView != null && mMenuView.isOverflowMenuShowing();
//    }

//    /** @hide */
//    @RestrictTo(LIBRARY_GROUP)
//    public boolean isOverflowMenuShowPending() {
//        return mMenuView != null && mMenuView.isOverflowMenuShowPending();
//    }

//    /**
//     * Show the overflow items from the associated menu.
//     *
//     * @return true if the menu was able to be shown, false otherwise
//     */
//    public boolean showOverflowMenu() {
//        return mMenuView != null && mMenuView.showOverflowMenu();
//    }

//    /**
//     * Hide the overflow items from the associated menu.
//     *
//     * @return true if the menu was able to be hidden, false otherwise
//     */
//    public boolean hideOverflowMenu() {
//        return mMenuView != null && mMenuView.hideOverflowMenu();
//    }

//    /** @hide */
//    @RestrictTo(LIBRARY_GROUP)
//    public void setMenu(MenuBuilder menu, ActionMenuPresenter outerPresenter) {
//        if (menu == null && mMenuView == null) {
//            return;
//        }
//
//        ensureMenuView();
//        final MenuBuilder oldMenu = mMenuView.peekMenu();
//        if (oldMenu == menu) {
//            return;
//        }
//
//        if (oldMenu != null) {
//            oldMenu.removeMenuPresenter(mOuterActionMenuPresenter);
//            oldMenu.removeMenuPresenter(mExpandedMenuPresenter);
//        }
//
//        if (mExpandedMenuPresenter == null) {
//            mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();
//        }
//
//        outerPresenter.setExpandedActionViewsExclusive(true);
//        if (menu != null) {
//            menu.addMenuPresenter(outerPresenter, mPopupContext);
//            menu.addMenuPresenter(mExpandedMenuPresenter, mPopupContext);
//        } else {
//            outerPresenter.initForMenu(mPopupContext, null);
//            mExpandedMenuPresenter.initForMenu(mPopupContext, null);
//            outerPresenter.updateMenuView(true);
//            mExpandedMenuPresenter.updateMenuView(true);
//        }
//        mMenuView.setPopupTheme(mPopupTheme);
//        mMenuView.setPresenter(outerPresenter);
//        mOuterActionMenuPresenter = outerPresenter;
//    }

//    /**
//     * Dismiss all currently showing popup menus, including overflow or submenus.
//     */
//    public void dismissPopupMenus() {
//        if (mMenuView != null) {
//            mMenuView.dismissPopupMenus();
//        }
//    }

//    /** @hide */
//    @RestrictTo(LIBRARY_GROUP)
//    public boolean isTitleTruncated() {
//        if (mTitleTextView == null) {
//            return false;
//        }
//
//        final Layout titleLayout = mTitleTextView.getLayout();
//        if (titleLayout == null) {
//            return false;
//        }
//
//        final int lineCount = titleLayout.getLineCount();
//        for (int i = 0; i < lineCount; i++) {
//            if (titleLayout.getEllipsisCount(i) > 0) {
//                return true;
//            }
//        }
//        return false;
//    }

    /**
     * Set a logo drawable.
     *
     * <p>This drawable should generally take the place of title text. The logo cannot be
     * clicked.
     *
     * @param drawable Drawable to use as a logo
     */
    public void setLogo(Element drawable) {
        if (drawable != null) {
            ensureLogoView();
            if (!isChildOrHidden(mLogoView)) {
                addSystemView(mLogoView, true);
            }
        } else if (mLogoView != null && isChildOrHidden(mLogoView)) {
            removeComponent(mLogoView);
            mHiddenViews.remove(mLogoView);
        }
        if (mLogoView != null) {
            mLogoView.setImageElement(drawable);
        }
    }

    /**
     * Return the current logo drawable.
     *
     * @return The current logo drawable
     * @see #setLogo(Element)
     */
    public Element getLogo() {
        return mLogoView != null ? mLogoView.getImageElement() : null;
    }

//    /**
//     * Set a description of the toolbar's logo.
//     *
//     * <p>This description will be used for accessibility or other similar descriptions
//     * of the UI.</p>
//     *
//     * @param resId String resource id
//     */
//    public void setLogoDescription(int resId) {
//        setLogoDescription(getContext().getString(resId));
//    }

//    /**
//     * Set a description of the toolbar's logo.
//     *
//     * <p>This description will be used for accessibility or other similar descriptions
//     * of the UI.</p>
//     *
//     * @param description Description to set
//     */
//    public void setLogoDescription(CharSequence description) {
//        if (!TextUtils.isEmpty(description)) {
//            ensureLogoView();
//        }
//        if (mLogoView != null) {
//            mLogoView.setContentDescription(description);
//        }
//    }

//    /**
//     * Return the description of the toolbar's logo.
//     *
//     * @return A description of the logo
//     */
//    public CharSequence getLogoDescription() {
//        return mLogoView != null ? mLogoView.getContentDescription() : null;
//    }

    private void ensureLogoView() {
        if (mLogoView == null) {
            mLogoView = new Image(getContext());
        }
    }

//    /**
//     * Check whether this Toolbar is currently hosting an expanded action view.
//     *
//     * <p>An action view may be expanded either directly from the
//     * {@link android.view.MenuItem MenuItem} it belongs to or by user action. If the Toolbar
//     * has an expanded action view it can be collapsed using the {@link #collapseActionView()}
//     * method.</p>
//     *
//     * @return true if the Toolbar has an expanded action view
//     */
//    public boolean hasExpandedActionView() {
//        return mExpandedMenuPresenter != null &&
//                mExpandedMenuPresenter.mCurrentExpandedItem != null;
//    }

//    /**
//     * Collapse a currently expanded action view. If this Toolbar does not have an
//     * expanded action view this method has no effect.
//     *
//     * <p>An action view may be expanded either directly from the
//     * {@link android.view.MenuItem MenuItem} it belongs to or by user action.</p>
//     *
//     * @see #hasExpandedActionView()
//     */
//    public void collapseActionView() {
//        final MenuItemImpl item = mExpandedMenuPresenter == null ? null :
//                mExpandedMenuPresenter.mCurrentExpandedItem;
//        if (item != null) {
//            item.collapseActionView();
//        }
//    }

    /**
     * Returns the title of this toolbar.
     *
     * @return The current title.
     */
    public String getTitle() {
        return mTitleText;
    }

    /**
     * Set the title of this toolbar.
     *
     * <p>A title should be used as the anchor for a section of content. It should
     * describe or name the content being viewed.</p>
     *
     * @param resId Resource ID of a string to set as the title
     */
    public void setTitle(int resId) {
        setTitle(getContext().getString(resId));
    }

    /**
     * Set the title of this toolbar.
     *
     * <p>A title should be used as the anchor for a section of content. It should
     * describe or name the content being viewed.</p>
     *
     * @param title Title to set
     */
    public void setTitle(String title) {
        if (!TextUtils.isEmpty(title)) {
            if (mTitleTextView == null) {
                final Context context = getContext();
                mTitleTextView = new Text(context);
                // ohos文字上方会有较大留白，导致视觉上不是垂直居中，所以设置一个PaddingBottom略做补充
                mTitleTextView.setPaddingBottom(6);
                mTitleTextView.setMaxTextLines(1);
                mTitleTextView.setTruncationMode(Text.TruncationMode.ELLIPSIS_AT_END);
                mTitleTextView.setTextAlignment(TextAlignment.TOP);
//                mTitleTextView.setBackground(new ShapeElement(getContext(), ResourceTable.Graphic_shape));
//                if (mTitleTextAppearance != 0) {
//                    mTitleTextView.setTextAppearance(mTitleTextAppearance);
//                }
                if (mTitleTextColor != 0) {
                    mTitleTextView.setTextColor(new Color(mTitleTextColor));
                }

                if (mTitleTextSize != 0) {
                    mTitleTextView.setTextSize(mTitleTextSize);
                }
            }
            if (!isChildOrHidden(mTitleTextView)) {
                addSystemView(mTitleTextView, true);
            }
        } else if (mTitleTextView != null && isChildOrHidden(mTitleTextView)) {
            removeComponent(mTitleTextView);
            mHiddenViews.remove(mTitleTextView);
        }
        if (mTitleTextView != null) {
            mTitleTextView.setText(title);
        }
        mTitleText = title;
    }

    /**
     * Return the subtitle of this toolbar.
     *
     * @return The current subtitle
     */
    public String getSubtitle() {
        return mSubtitleText;
    }

    /**
     * Set the subtitle of this toolbar.
     *
     * <p>Subtitles should express extended information about the current content.</p>
     *
     * @param resId String resource ID
     */
    public void setSubtitle(int resId) {
        setSubtitle(getContext().getString(resId));
    }

    /**
     * Set the subtitle of this toolbar.
     *
     * <p>Subtitles should express extended information about the current content.</p>
     *
     * @param subtitle Subtitle to set
     */
    public void setSubtitle(String subtitle) {
        if (!TextUtils.isEmpty(subtitle)) {
            if (mSubtitleTextView == null) {
                final Context context = getContext();
                mSubtitleTextView = new Text(context);
                mSubtitleTextView.setMaxTextLines(1);
                mSubtitleTextView.setTruncationMode(Text.TruncationMode.ELLIPSIS_AT_END);
//                if (mSubtitleTextAppearance != 0) {
//                    mSubtitleTextView.setTextAppearance(context, mSubtitleTextAppearance);
//                }
                if (mSubtitleTextColor != 0) {
                    mSubtitleTextView.setTextColor(new Color(mSubtitleTextColor));
                }

                if (mSubtitleTextSize != 0) {
                    mSubtitleTextView.setTextSize(mSubtitleTextSize);
                }
            }
            if (!isChildOrHidden(mSubtitleTextView)) {
                addSystemView(mSubtitleTextView, true);
            }
        } else if (mSubtitleTextView != null && isChildOrHidden(mSubtitleTextView)) {
            removeComponent(mSubtitleTextView);
            mHiddenViews.remove(mSubtitleTextView);
        }
        if (mSubtitleTextView != null) {
            mSubtitleTextView.setText(subtitle);
        }
        mSubtitleText = subtitle;
    }

//    /**
//     * Sets the text color, size, style, hint color, and highlight color
//     * from the specified TextAppearance resource.
//     */
//    public void setTitleTextAppearance(Context context, @StyleRes int resId) {
//        mTitleTextAppearance = resId;
//        if (mTitleTextView != null) {
//            mTitleTextView.setTextAppearance(context, resId);
//        }
//    }

//    /**
//     * Sets the text color, size, style, hint color, and highlight color
//     * from the specified TextAppearance resource.
//     */
//    public void setSubtitleTextAppearance(Context context, int resId) {
//        mSubtitleTextAppearance = resId;
//        if (mSubtitleTextView != null) {
//            mSubtitleTextView.setTextAppearance(context, resId);
//        }
//    }

    /**
     * Sets the text color of the title, if present.
     *
     * @param color The new text color in 0xAARRGGBB format
     */
    public void setTitleTextColor(int color) {
        mTitleTextColor = color;
        if (mTitleTextView != null) {
            mTitleTextView.setTextColor(new Color(color));
        }
    }

    /**
     * Sets the text color of the subtitle, if present.
     *
     * @param color The new text color in 0xAARRGGBB format
     */
    public void setSubtitleTextColor(int color) {
        mSubtitleTextColor = color;
        if (mSubtitleTextView != null) {
            mSubtitleTextView.setTextColor(new Color(color));
        }
    }

    /**
     * Sets the text size of the title, if present.
     *
     * @param size The new text size
     */
    public void setTitleTextSize(int size) {
        mTitleTextSize = size;
        if (mTitleTextView != null) {
            mTitleTextView.setTextSize(size);
        }
    }

    /**
     * Sets the text size of the subtitle, if present.
     *
     * @param size The new text size
     */
    public void setSubtitleTextSize(int size) {
        mSubtitleTextSize = size;
        if (mSubtitleTextView != null) {
            mSubtitleTextView.setTextSize(size);
        }
    }

//    /**
//     * Retrieve the currently configured content description for the navigation button view.
//     * This will be used to describe the navigation action to users through mechanisms such
//     * as screen readers or tooltips.
//     *
//     * @return The navigation button's content description
//     *
//     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_navigationContentDescription
//     */
//    @Nullable
//    public CharSequence getNavigationContentDescription() {
//        return mNavButtonView != null ? mNavButtonView.getContentDescription() : null;
//    }

//    /**
//     * Set a content description for the navigation button if one is present. The content
//     * description will be read via screen readers or other accessibility systems to explain
//     * the action of the navigation button.
//     *
//     * @param resId Resource ID of a content description string to set, or 0 to
//     *              clear the description
//     *
//     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_navigationContentDescription
//     */
//    public void setNavigationContentDescription(@StringRes int resId) {
//        setNavigationContentDescription(resId != 0 ? getContext().getText(resId) : null);
//    }

//    /**
//     * Set a content description for the navigation button if one is present. The content
//     * description will be read via screen readers or other accessibility systems to explain
//     * the action of the navigation button.
//     *
//     * @param description Content description to set, or <code>null</code> to
//     *                    clear the content description
//     *
//     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_navigationContentDescription
//     */
//    public void setNavigationContentDescription(@Nullable CharSequence description) {
//        if (!TextUtils.isEmpty(description)) {
//            ensureNavButtonView();
//        }
//        if (mNavButtonView != null) {
//            mNavButtonView.setContentDescription(description);
//        }
//    }

//    /**
//     * Set the icon to use for the toolbar's navigation button.
//     *
//     * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
//     * will make the navigation button visible.</p>
//     *
//     * @param resId Resource ID of a drawable to set
//     */
//    public void setNavigationIcon(int resId) {
//        if (resId != 0) {
//            ensureNavButtonView();
//            if (!isChildOrHidden(mNavButtonView)) {
//                addSystemView(mNavButtonView, true);
//            }
//        } else if (mNavButtonView != null && isChildOrHidden(mNavButtonView)) {
//            removeComponent(mNavButtonView);
//            mHiddenViews.remove(mNavButtonView);
//        }
//        if (mNavButtonView != null) {
//            mNavButtonView.setImageAndDecodeBounds(resId);
//        }
//    }

    /**
     * Set the icon to use for the toolbar's navigation button.
     *
     * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
     * will make the navigation button visible.</p>
     *
     * @param icon Drawable to set, may be null to clear the icon
     */
    public void setNavigationIcon(Element icon) {
        if (icon != null) {
            ensureNavButtonView();
            if (!isChildOrHidden(mNavButtonLayout)) {
                addSystemView(mNavButtonLayout, true);
            }
        } else if (mNavButtonLayout != null && isChildOrHidden(mNavButtonLayout)) {
            removeComponent(mNavButtonLayout);
            mHiddenViews.remove(mNavButtonLayout);
        }
        if (mNavButtonLayout != null && mNavButtonView != null) {
            mNavButtonView.setImageElement(icon);
        }
    }

    /**
     * Return the current drawable used as the navigation icon.
     *
     * @return The navigation icon drawable
     */
    public Element getNavigationIcon() {
        return mNavButtonView != null ? mNavButtonView.getImageElement() : null;
    }

    /**
     * Set a listener to respond to navigation events.
     *
     * <p>This listener will be called whenever the user clicks the navigation button
     * at the start of the toolbar. An icon must be set for the navigation button to appear.</p>
     *
     * @param listener Listener to set
     */
    public void setNavigationOnClickListener(ClickedListener listener) {
        ensureNavButtonView();
        mNavButtonLayout.setClickedListener(listener);
    }

//    /**
//     * Return the Menu shown in the toolbar.
//     *
//     * <p>Applications that wish to populate the toolbar's menu can do so from here. To use
//     * an XML menu resource, use {@link #inflateMenu(int)}.</p>
//     *
//     * @return The toolbar's Menu
//     */
//    public Menu getMenu() {
//        ensureMenu();
//        return mMenuView.getMenu();
//    }

//    /**
//     * Set the icon to use for the overflow button.
//     *
//     * @param icon Drawable to set, may be null to clear the icon
//     */
//    public void setOverflowIcon(@Nullable Drawable icon) {
//        ensureMenu();
//        mMenuView.setOverflowIcon(icon);
//    }

//    /**
//     * Return the current drawable used as the overflow icon.
//     *
//     * @return The overflow icon drawable
//     */
//    public Drawable getOverflowIcon() {
//        ensureMenu();
//        return mMenuView.getOverflowIcon();
//    }

//    private void ensureMenu() {
//        ensureMenuView();
//        if (mMenuView.peekMenu() == null) {
//            // Initialize a new menu for the first time.
//            final MenuBuilder menu = (MenuBuilder) mMenuView.getMenu();
//            if (mExpandedMenuPresenter == null) {
//                mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();
//            }
//            mMenuView.setExpandedActionViewsExclusive(true);
//            menu.addMenuPresenter(mExpandedMenuPresenter, mPopupContext);
//        }
//    }

//    private void ensureMenuView() {
//        if (mMenuView == null) {
//            mMenuView = new ActionMenuView(getContext());
//            mMenuView.setPopupTheme(mPopupTheme);
//            mMenuView.setOnMenuItemClickListener(mMenuViewItemClickListener);
//            mMenuView.setMenuCallbacks(mActionMenuPresenterCallback, mMenuBuilderCallback);
//            final LayoutParams lp = generateDefaultLayoutParams();
//            lp.gravity = GravityCompat.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
//            mMenuView.setLayoutParams(lp);
//            addSystemView(mMenuView, false);
//        }
//    }

//    private MenuInflater getMenuInflater() {
//        return new SupportMenuInflater(getContext());
//    }

//    /**
//     * Inflate a menu resource into this toolbar.
//     *
//     * <p>Inflate an XML menu resource into this toolbar. Existing items in the menu will not
//     * be modified or removed.</p>
//     *
//     * @param resId ID of a menu resource to inflate
//     */
//    public void inflateMenu(@MenuRes int resId) {
//        getMenuInflater().inflate(resId, getMenu());
//    }

//    /**
//     * Set a listener to respond to menu item click events.
//     *
//     * <p>This listener will be invoked whenever a user selects a menu item from
//     * the action buttons presented at the end of the toolbar or the associated overflow.</p>
//     *
//     * @param listener Listener to set
//     */
//    public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
//        mOnMenuItemClickListener = listener;
//    }

    /**
     * Sets the content insets for this toolbar relative to layout direction.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @param contentInsetStart Content inset for the toolbar starting edge
     * @param contentInsetEnd   Content inset for the toolbar ending edge
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetEnd
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetStart
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetStart()
     * @see #getContentInsetEnd()
     * @see #getContentInsetLeft()
     * @see #getContentInsetRight()
     */
    public void setContentInsetsRelative(int contentInsetStart, int contentInsetEnd) {
        ensureContentInsets();
        mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
    }

    /**
     * Gets the starting content inset for this toolbar.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @return The starting content inset for this toolbar
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetStart
     * @see #setContentInsetsRelative(int, int)
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetEnd()
     * @see #getContentInsetLeft()
     * @see #getContentInsetRight()
     */
    public int getContentInsetStart() {
        return mContentInsets != null ? mContentInsets.getStart() : 0;
    }

    /**
     * Gets the ending content inset for this toolbar.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @return The ending content inset for this toolbar
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetEnd
     * @see #setContentInsetsRelative(int, int)
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetStart()
     * @see #getContentInsetLeft()
     * @see #getContentInsetRight()
     */
    public int getContentInsetEnd() {
        return mContentInsets != null ? mContentInsets.getEnd() : 0;
    }

    /**
     * Sets the content insets for this toolbar.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @param contentInsetLeft  Content inset for the toolbar's left edge
     * @param contentInsetRight Content inset for the toolbar's right edge
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetLeft
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetRight
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetStart()
     * @see #getContentInsetEnd()
     * @see #getContentInsetLeft()
     * @see #getContentInsetRight()
     */
    public void setContentInsetsAbsolute(int contentInsetLeft, int contentInsetRight) {
        ensureContentInsets();
        mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
    }

    /**
     * Gets the left content inset for this toolbar.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @return The left content inset for this toolbar
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetLeft
     * @see #setContentInsetsRelative(int, int)
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetStart()
     * @see #getContentInsetEnd()
     * @see #getContentInsetRight()
     */
    public int getContentInsetLeft() {
        return mContentInsets != null ? mContentInsets.getLeft() : 0;
    }

    /**
     * Gets the right content inset for this toolbar.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @return The right content inset for this toolbar
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetRight
     * @see #setContentInsetsRelative(int, int)
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetStart()
     * @see #getContentInsetEnd()
     * @see #getContentInsetLeft()
     */
    public int getContentInsetRight() {
        return mContentInsets != null ? mContentInsets.getRight() : 0;
    }

    /**
     * Gets the start content inset to use when a navigation button is present.
     *
     * <p>Different content insets are often called for when additional buttons are present
     * in the toolbar, as well as at different toolbar sizes. The larger value of
     * {@link #getContentInsetStart()} and this value will be used during layout.</p>
     *
     * @return the start content inset used when a navigation icon has been set in pixels
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetStartWithNavigation
     * @see #setContentInsetStartWithNavigation(int)
     */
    public int getContentInsetStartWithNavigation() {
        return mContentInsetStartWithNavigation != RtlSpacingHelper.UNDEFINED
                ? mContentInsetStartWithNavigation
                : getContentInsetStart();
    }

    /**
     * Sets the start content inset to use when a navigation button is present.
     *
     * <p>Different content insets are often called for when additional buttons are present
     * in the toolbar, as well as at different toolbar sizes. The larger value of
     * {@link #getContentInsetStart()} and this value will be used during layout.</p>
     *
     * @param insetStartWithNavigation the inset to use when a navigation icon has been set
     *                                 in pixels
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetStartWithNavigation
     * @see #getContentInsetStartWithNavigation()
     */
    public void setContentInsetStartWithNavigation(int insetStartWithNavigation) {
        if (insetStartWithNavigation < 0) {
            insetStartWithNavigation = RtlSpacingHelper.UNDEFINED;
        }
        if (insetStartWithNavigation != mContentInsetStartWithNavigation) {
            mContentInsetStartWithNavigation = insetStartWithNavigation;
            if (getNavigationIcon() != null) {
                postLayout();
            }
        }
    }

    /**
     * Gets the end content inset to use when action buttons are present.
     *
     * <p>Different content insets are often called for when additional buttons are present
     * in the toolbar, as well as at different toolbar sizes. The larger value of
     * {@link #getContentInsetEnd()} and this value will be used during layout.</p>
     *
     * @return the end content inset used when a menu has been set in pixels
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetEndWithActions
     * @see #setContentInsetEndWithActions(int)
     */
    public int getContentInsetEndWithActions() {
        return mContentInsetEndWithActions != RtlSpacingHelper.UNDEFINED
                ? mContentInsetEndWithActions
                : getContentInsetEnd();
    }

    /**
     * Sets the start content inset to use when action buttons are present.
     *
     * <p>Different content insets are often called for when additional buttons are present
     * in the toolbar, as well as at different toolbar sizes. The larger value of
     * {@link #getContentInsetEnd()} and this value will be used during layout.</p>
     *
     * @param insetEndWithActions the inset to use when a menu has been set in pixels
     * @attr ref android.support.v7.appcompat.R.styleable#Toolbar_contentInsetEndWithActions
     * @see #getContentInsetEndWithActions()
     */
    public void setContentInsetEndWithActions(int insetEndWithActions) {
        if (insetEndWithActions < 0) {
            insetEndWithActions = RtlSpacingHelper.UNDEFINED;
        }
        if (insetEndWithActions != mContentInsetEndWithActions) {
            mContentInsetEndWithActions = insetEndWithActions;
            if (getNavigationIcon() != null) {
                postLayout();
            }
        }
    }

    /**
     * Gets the content inset that will be used on the starting side of the bar in the current
     * toolbar configuration.
     *
     * @return the current content inset start in pixels
     * @see #getContentInsetStartWithNavigation()
     */
    public int getCurrentContentInsetStart() {
        return getNavigationIcon() != null
                ? Math.max(getContentInsetStart(), Math.max(mContentInsetStartWithNavigation, 0))
                : getContentInsetStart();
    }

    /**
     * Gets the content inset that will be used on the ending side of the bar in the current
     * toolbar configuration.
     *
     * @return the current content inset end in pixels
     * @see #getContentInsetEndWithActions()
     */
    public int getCurrentContentInsetEnd() {
        boolean hasActions = false;
//        if (mMenuView != null) {
//            final MenuBuilder mb = mMenuView.peekMenu();
//            hasActions = mb != null && mb.hasVisibleItems();
//        }
        return hasActions
                ? Math.max(getContentInsetEnd(), Math.max(mContentInsetEndWithActions, 0))
                : getContentInsetEnd();
    }

    /**
     * Gets the content inset that will be used on the left side of the bar in the current
     * toolbar configuration.
     *
     * @return the current content inset left in pixels
     * @see #getContentInsetStartWithNavigation()
     * @see #getContentInsetEndWithActions()
     */
    public int getCurrentContentInsetLeft() {
        return getLayoutDirection() == LayoutDirection.RTL
                ? getCurrentContentInsetEnd()
                : getCurrentContentInsetStart();
    }

    /**
     * Gets the content inset that will be used on the right side of the bar in the current
     * toolbar configuration.
     *
     * @return the current content inset right in pixels
     * @see #getContentInsetStartWithNavigation()
     * @see #getContentInsetEndWithActions()
     */
    public int getCurrentContentInsetRight() {
        return getLayoutDirection() == LayoutDirection.RTL
                ? getCurrentContentInsetStart()
                : getCurrentContentInsetEnd();
    }

    private void ensureStatusBarView() {
        if (mStatusBarView == null) {
            mStatusBarView = new Component(getContext());
            final LayoutParams lp = new LayoutParams(LayoutConfig.MATCH_PARENT, mStatusBarHeight);
            lp.gravity = Gravity.NO_GRAVITY;
            lp.mViewType = LayoutParams.SYSTEM;
            mStatusBarView.setLayoutConfig(lp);

            addComponent(mStatusBarView);
        }
    }

    private void ensureNavButtonView() {
        if (mNavButtonLayout == null) {
            mNavButtonLayout = new DirectionalLayout(getContext());
            final LayoutParams lp;
            if (mNavigationIconWidth <= 0) {
                lp = generateDefaultLayoutParams();
            } else {
                lp = new LayoutParams(mNavigationIconWidth, LayoutConfig.MATCH_CONTENT);
            }
            lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
            mNavButtonLayout.setAlignment(LayoutAlignment.CENTER);
            mNavButtonLayout.setLayoutConfig(lp);


            mNavButtonView = new Image(getContext(), null);
            mNavButtonView.setLayoutConfig(generateDefaultLayoutParams());
            mNavButtonLayout.addComponent(mNavButtonView);

            mNavButtonLayout.setClickedListener(v -> {
                getContext().terminateAbility();
            });
        }
    }

    void ensureCollapseButtonView() {
        if (mCollapseButtonView == null) {
            mCollapseButtonView = new Image(getContext(), null);
            // R.attr.toolbarNavigationButtonStyle);
            mCollapseButtonView.setImageElement(mCollapseIcon);
//            mCollapseButtonView.setContentDescription(mCollapseDescription);
            final LayoutParams lp = new LayoutParams(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
            lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
            lp.mViewType = LayoutParams.EXPANDED;
            mCollapseButtonView.setLayoutConfig(lp);
            mCollapseButtonView.setClickedListener(v -> {
//                    collapseActionView();
            });
        }
    }

    private void addSystemView(Component v, boolean allowHide) {
        final LayoutConfig vlp = v.getLayoutConfig();
        final LayoutParams lp;
        if (vlp == null) {
            lp = generateDefaultLayoutParams();
        } else if (!checkLayoutParams(vlp)) {
            lp = new LayoutParams(vlp);
        } else {
            lp = (LayoutParams) vlp;
        }
        lp.mViewType = LayoutParams.SYSTEM;

        if (allowHide && mExpandedActionView != null) {
            v.setLayoutConfig(lp);
            mHiddenViews.add(v);
        } else {
            addComponent(v, lp);
        }
    }

//    @Override
//    protected Parcelable onSaveInstanceState() {
//        SavedState state = new SavedState(super.onSaveInstanceState());
//
//        if (mExpandedMenuPresenter != null && mExpandedMenuPresenter.mCurrentExpandedItem != null) {
//            state.expandedMenuItemId = mExpandedMenuPresenter.mCurrentExpandedItem.getItemId();
//        }
//
//        state.isOverflowOpen = isOverflowMenuShowing();
//        return state;
//    }

//    @Override
//    protected void onRestoreInstanceState(Parcelable state) {
//        if (!(state instanceof SavedState)) {
//            super.onRestoreInstanceState(state);
//            return;
//        }
//
//        final SavedState ss = (SavedState) state;
//        super.onRestoreInstanceState(ss.getSuperState());
//
//        final Menu menu = mMenuView != null ? mMenuView.peekMenu() : null;
//        if (ss.expandedMenuItemId != 0 && mExpandedMenuPresenter != null && menu != null) {
//            final MenuItem item = menu.findItem(ss.expandedMenuItemId);
//            if (item != null) {
//                MenuItemCompat.expandActionView(item);
//            }
//        }
//
//        if (ss.isOverflowOpen) {
//            postShowOverflowMenu();
//        }
//    }

//    private void postShowOverflowMenu() {
//        removeCallbacks(mShowOverflowMenuRunnable);
//        post(mShowOverflowMenuRunnable);
//    }

//    @Override
//    protected void onDetachedFromWindow() {
//        super.onDetachedFromWindow();
//        removeCallbacks(mShowOverflowMenuRunnable);
//    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        return DispatchHelper.dispatch(component, touchEvent);
    }

    // ViewGroup

    @Override
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        mViewGroupHelper.requestDisallowInterceptTouchEvent(disallowIntercept);
    }

    @Override
    public boolean onInterceptTouchEvent(TouchEvent ev) {
        return false;
    }

    @Override
    public boolean dispatchTouchEvent(TouchEvent event) {
        return mViewGroupHelper.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(TouchEvent ev) {
        // Toolbars always eat touch events, but should still respect the touch event dispatch
        // contract. If the normal View implementation doesn't want the events, we'll just silently
        // eat the rest of the gesture without reporting the events to the default implementation
        // since that's what it expects.

        final int action = ev.getAction();
        if (action == TouchEvent.PRIMARY_POINT_DOWN) {
            mEatingTouch = false;
        }

        if (!mEatingTouch) {
//            final boolean handled = false;
            if (action == TouchEvent.PRIMARY_POINT_DOWN) {
                mEatingTouch = true;
            }
        }

        if (action == TouchEvent.PRIMARY_POINT_UP || action == TouchEvent.CANCEL) {
            mEatingTouch = false;
        }

        return true;
    }

    @Override
    public boolean isConsumed() {
        return mViewGroupHelper.isConsumed();
    }

//    @Override
//    public boolean onHoverEvent(MotionEvent ev) {
//        // Same deal as onTouchEvent() above. Eat all hover events, but still
//        // respect the touch event dispatch contract.
//
//        final int action = MotionEventCompat.getActionMasked(ev);
//        if (action == MotionEvent.ACTION_HOVER_ENTER) {
//            mEatingHover = false;
//        }
//
//        if (!mEatingHover) {
//            final boolean handled = super.onHoverEvent(ev);
//            if (action == MotionEvent.ACTION_HOVER_ENTER && !handled) {
//                mEatingHover = true;
//            }
//        }
//
//        if (action == MotionEvent.ACTION_HOVER_EXIT || action == MotionEvent.ACTION_CANCEL) {
//            mEatingHover = false;
//        }
//
//        return true;
//    }

    private void measureChildConstrained(Component child, int parentWidthSpec, int widthUsed,
                                         int parentHeightSpec, int heightUsed, int heightConstraint) {
        final LayoutConfig lp = child.getLayoutConfig();

        int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
                getPaddingLeft() + getPaddingRight() + lp.getMarginLeft() + lp.getMarginRight()
                        + widthUsed, lp.width);
        int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
                getPaddingTop() + getPaddingBottom() + lp.getMarginTop() + lp.getMarginBottom()
                        + heightUsed, lp.height);

        final int childHeightMode = EstimateSpec.getMode(childHeightSpec);
        if (childHeightMode != EstimateSpec.PRECISE && heightConstraint >= 0) {
            final int size = childHeightMode != EstimateSpec.UNCONSTRAINT ?
                    Math.min(EstimateSpec.getSize(childHeightSpec), heightConstraint) :
                    heightConstraint;
            childHeightSpec = EstimateHelper.makeEstimateSpec(size, EstimateSpec.PRECISE);
        }
        child.estimateSize(childWidthSpec, childHeightSpec);
    }

    /**
     * Returns the width + uncollapsed margins
     */
    private int measureChildCollapseMargins(Component child,
                                            int parentWidthMeasureSpec, int widthUsed,
                                            int parentHeightMeasureSpec, int heightUsed, int[] collapsingMargins) {
        final LayoutConfig lp = child.getLayoutConfig();

        final int leftDiff = lp.getMarginLeft() - collapsingMargins[0];
        final int rightDiff = lp.getMarginRight() - collapsingMargins[1];
        final int leftMargin = Math.max(0, leftDiff);
        final int rightMargin = Math.max(0, rightDiff);
        final int hMargins = leftMargin + rightMargin;
        collapsingMargins[0] = Math.max(0, -leftDiff);
        collapsingMargins[1] = Math.max(0, -rightDiff);

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                getPaddingLeft() + getPaddingRight() + hMargins + widthUsed, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                getPaddingTop() + getPaddingBottom() + lp.getMarginTop() + lp.getMarginBottom()
                        + heightUsed, lp.height);

        child.estimateSize(childWidthMeasureSpec, childHeightMeasureSpec);
        return child.getEstimatedWidth() + hMargins;
    }

    /**
     * Returns true if the Toolbar is collapsible and has no child views with a measured size > 0.
     */
    private boolean shouldCollapse() {
        if (!mCollapsible) return false;

        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            final Component child = getComponentAt(i);
            if (shouldLayout(child) && child.getEstimatedWidth() > 0 &&
                    child.getEstimatedHeight() > 0) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        int width = 0;
        int height = 0;
//        int childState = 0;

        final int[] collapsingMargins = mTempMargins;
        final int marginStartIndex;
        final int marginEndIndex;
        if (getLayoutDirection() == LayoutDirection.RTL) {
            marginStartIndex = 1;
            marginEndIndex = 0;
        } else {
            marginStartIndex = 0;
            marginEndIndex = 1;
        }

        // System views measure first.

        int navWidth = 0;
        if (shouldLayout(mStatusBarView)) {
            measureChildConstrained(mStatusBarView, widthMeasureSpec, width, heightMeasureSpec, 0,
                    mStatusBarHeight);
        }

        if (shouldLayout(mNavButtonLayout)) {
            measureChildConstrained(mNavButtonLayout, widthMeasureSpec, width, heightMeasureSpec, 0,
                    mMaxButtonHeight);
            navWidth = mNavButtonLayout.getEstimatedWidth() + getHorizontalMargins(mNavButtonLayout);
            height = Math.max(height, mNavButtonLayout.getEstimatedHeight() +
                    getVerticalMargins(mNavButtonLayout));
//            childState = ViewUtils.combineMeasuredStates(childState,
//                    ViewCompat.getMeasuredState(mNavButtonView));
        }

        if (shouldLayout(mCollapseButtonView)) {
            measureChildConstrained(mCollapseButtonView, widthMeasureSpec, width,
                    heightMeasureSpec, 0, mMaxButtonHeight);
            navWidth = mCollapseButtonView.getEstimatedWidth() +
                    getHorizontalMargins(mCollapseButtonView);
            height = Math.max(height, mCollapseButtonView.getEstimatedHeight() +
                    getVerticalMargins(mCollapseButtonView));
//            childState = ViewUtils.combineMeasuredStates(childState,
//                    ViewCompat.getMeasuredState(mCollapseButtonView));
        }

        final int contentInsetStart = getCurrentContentInsetStart();
        width += Math.max(contentInsetStart, navWidth);
        collapsingMargins[marginStartIndex] = Math.max(0, contentInsetStart - navWidth);

//        int menuWidth = 0;
//        if (shouldLayout(mMenuView)) {
//            measureChildConstrained(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0,
//                    mMaxButtonHeight);
//            menuWidth = mMenuView.getEstimatedWidth() + getHorizontalMargins(mMenuView);
//            height = Math.max(height, mMenuView.getEstimatedHeight() +
//                    getVerticalMargins(mMenuView));
//            childState = ViewUtils.combineMeasuredStates(childState,
//                    ViewCompat.getMeasuredState(mMenuView));
//        }

        final int contentInsetEnd = getCurrentContentInsetEnd();
        width += contentInsetEnd; // Math.max(contentInsetEnd, menuWidth);
        collapsingMargins[marginEndIndex] = Math.max(0, contentInsetEnd); // Math.max(0, contentInsetEnd - menuWidth);

        if (shouldLayout(mExpandedActionView)) {
            width += measureChildCollapseMargins(mExpandedActionView, widthMeasureSpec, width,
                    heightMeasureSpec, 0, collapsingMargins);
            height = Math.max(height, mExpandedActionView.getEstimatedHeight() +
                    getVerticalMargins(mExpandedActionView));
//            childState = ViewUtils.combineMeasuredStates(childState,
//                    ViewCompat.getMeasuredState(mExpandedActionView));
        }

        if (shouldLayout(mLogoView)) {
            width += measureChildCollapseMargins(mLogoView, widthMeasureSpec, width,
                    heightMeasureSpec, 0, collapsingMargins);
            height = Math.max(height, mLogoView.getEstimatedHeight() +
                    getVerticalMargins(mLogoView));
//            childState = ViewUtils.combineMeasuredStates(childState,
//                    ViewCompat.getMeasuredState(mLogoView));
        }

        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            final Component child = getComponentAt(i);
            final LayoutParams lp = (LayoutParams) child.getLayoutConfig();
            if (lp.mViewType != LayoutParams.CUSTOM || !shouldLayout(child)) {
                // We already got all system views above. Skip them and GONE views.
                continue;
            }

            width += measureChildCollapseMargins(child, widthMeasureSpec, width,
                    heightMeasureSpec, 0, collapsingMargins);
            height = Math.max(height, child.getEstimatedHeight() + getVerticalMargins(child));
//            childState = ViewUtils.combineMeasuredStates(childState,
//                    ViewCompat.getMeasuredState(child));
        }

        int titleWidth = 0;
        int titleHeight = 0;
        final int titleVertMargins = mTitleMarginTop + mTitleMarginBottom;
        final int titleHorizMargins = mTitleMarginStart + mTitleMarginEnd;
        if (shouldLayout(mTitleTextView)) {
            titleWidth = measureChildCollapseMargins(mTitleTextView, widthMeasureSpec,
                    width + titleHorizMargins, heightMeasureSpec, titleVertMargins,
                    collapsingMargins);
            titleWidth = mTitleTextView.getEstimatedWidth() + getHorizontalMargins(mTitleTextView);
            titleHeight = mTitleTextView.getEstimatedHeight() + getVerticalMargins(mTitleTextView);
//            childState = ViewUtils.combineMeasuredStates(childState,
//                    ViewCompat.getMeasuredState(mTitleTextView));
        }
        if (shouldLayout(mSubtitleTextView)) {
            titleWidth = Math.max(titleWidth, measureChildCollapseMargins(mSubtitleTextView,
                    widthMeasureSpec, width + titleHorizMargins,
                    heightMeasureSpec, titleHeight + titleVertMargins,
                    collapsingMargins));
            titleHeight += mSubtitleTextView.getEstimatedHeight() +
                    getVerticalMargins(mSubtitleTextView);
//            childState = ViewUtils.combineMeasuredStates(childState,
//                    ViewCompat.getMeasuredState(mSubtitleTextView));
        }

        width += titleWidth;
        height = Math.max(height, titleHeight);

        // Measurement already took padding into account for available space for the children,
        // add it in for the final size.
        width += getPaddingLeft() + getPaddingRight();
        height += getPaddingTop() + getPaddingBottom() + mStatusBarHeight;

        int mode = EstimateSpec.getMode(heightMeasureSpec);
        int size = EstimateSpec.getSize(heightMeasureSpec);
        if (mode == EstimateSpec.PRECISE) {
            heightMeasureSpec = EstimateHelper.makeEstimateSpec(size + mStatusBarHeight, mode);
        }

        final int measuredWidth = resolveSize(Math.max(width, getMinWidth()), widthMeasureSpec);
        final int measuredHeight = resolveSize(Math.max(height, getMinHeight()), heightMeasureSpec);

        setEstimatedSize(measuredWidth, shouldCollapse() ? 0 : measuredHeight);
        return true;
    }

    @Override
    public boolean onArrange(int l, int t, int width, int height) {
        final boolean isRtl = getLayoutDirection() == LayoutDirection.RTL;
        final int r = l + getWidth();
        final int b = t + getHeight();
        final int paddingLeft = getPaddingLeft();
        final int paddingRight = getPaddingRight();
        final int paddingTop = getPaddingTop();
        final int paddingBottom = getPaddingBottom();
        int left = paddingLeft;
        int right = width - paddingRight;
        int topAppend = mStatusBarHeight / 2;

        final int[] collapsingMargins = mTempMargins;
        collapsingMargins[0] = collapsingMargins[1] = 0;

        // Align views within the minimum toolbar height, if set.
        final int minHeight = getMinHeight();
        final int alignmentHeight = minHeight >= 0 ? Math.min(minHeight, b - t) - mStatusBarHeight : 0;

        if (shouldLayout(mStatusBarView)) {
            mStatusBarView.arrange(0, 0, mStatusBarView.getEstimatedWidth(), mStatusBarHeight);
        }

        if (shouldLayout(mNavButtonLayout)) {
            if (isRtl) {
                right = layoutChildRight(mNavButtonLayout, right, collapsingMargins,
                        alignmentHeight);
            } else {
                left = layoutChildLeft(mNavButtonLayout, left, collapsingMargins,
                        alignmentHeight);
            }
        }

        if (shouldLayout(mCollapseButtonView)) {
            if (isRtl) {
                right = layoutChildRight(mCollapseButtonView, right, collapsingMargins,
                        alignmentHeight);
            } else {
                left = layoutChildLeft(mCollapseButtonView, left, collapsingMargins,
                        alignmentHeight);
            }
        }

//        if (shouldLayout(mMenuView)) {
//            if (isRtl) {
//                left = layoutChildLeft(mMenuView, left, collapsingMargins,
//                        alignmentHeight);
//            } else {
//                right = layoutChildRight(mMenuView, right, collapsingMargins,
//                        alignmentHeight);
//            }
//        }

        final int contentInsetLeft = getCurrentContentInsetLeft();
        final int contentInsetRight = getCurrentContentInsetRight();
        collapsingMargins[0] = Math.max(0, contentInsetLeft - left);
        collapsingMargins[1] = Math.max(0, contentInsetRight - (width - paddingRight - right));
        left = Math.max(left, contentInsetLeft);
        right = Math.min(right, width - paddingRight - contentInsetRight);

        if (shouldLayout(mExpandedActionView)) {
            if (isRtl) {
                right = layoutChildRight(mExpandedActionView, right, collapsingMargins,
                        alignmentHeight);
            } else {
                left = layoutChildLeft(mExpandedActionView, left, collapsingMargins,
                        alignmentHeight);
            }
        }

        if (shouldLayout(mLogoView)) {
            if (isRtl) {
                right = layoutChildRight(mLogoView, right, collapsingMargins,
                        alignmentHeight);
            } else {
                left = layoutChildLeft(mLogoView, left, collapsingMargins,
                        alignmentHeight);
            }
        }

        final boolean layoutTitle = shouldLayout(mTitleTextView);
        final boolean layoutSubtitle = shouldLayout(mSubtitleTextView);
        int titleHeight = 0;
        if (layoutTitle) {
            final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutConfig();
            titleHeight += lp.getMarginTop() + mTitleTextView.getEstimatedHeight() + lp.getMarginBottom();
        }
        if (layoutSubtitle) {
            final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutConfig();
            titleHeight += lp.getMarginTop() + mSubtitleTextView.getEstimatedHeight() + lp.getMarginBottom();
        }

        if (layoutTitle || layoutSubtitle) {
            int titleTop;
            final Component topChild = layoutTitle ? mTitleTextView : mSubtitleTextView;
            final Component bottomChild = layoutSubtitle ? mSubtitleTextView : mTitleTextView;
            final LayoutParams toplp = (LayoutParams) topChild.getLayoutConfig();
            final LayoutParams bottomlp = (LayoutParams) bottomChild.getLayoutConfig();
            final boolean titleHasWidth = (layoutTitle && mTitleTextView.getEstimatedWidth() > 0)
                    || (layoutSubtitle && mSubtitleTextView.getEstimatedWidth() > 0);

            switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
                case Gravity.TOP:
                    titleTop = getPaddingTop() + toplp.getMarginTop() + mTitleMarginTop + mStatusBarHeight;
                    break;
                default:
                case Gravity.CENTER_VERTICAL:
                    final int space = height - paddingTop - paddingBottom;
                    int spaceAbove = (space - titleHeight) / 2;
                    if (spaceAbove < toplp.getMarginTop() + mTitleMarginTop) {
                        spaceAbove = toplp.getMarginTop() + mTitleMarginTop;
                    } else {
                        final int spaceBelow = height - paddingBottom - titleHeight -
                                spaceAbove - paddingTop;
                        if (spaceBelow < toplp.getMarginBottom() + mTitleMarginBottom) {
                            spaceAbove = Math.max(0, spaceAbove -
                                    (bottomlp.getMarginBottom() + mTitleMarginBottom - spaceBelow));
                        }
                    }
                    titleTop = paddingTop + spaceAbove + topAppend;
                    break;
                case Gravity.BOTTOM:
                    titleTop = height - paddingBottom - bottomlp.getMarginBottom() - mTitleMarginBottom -
                            titleHeight + mStatusBarHeight;
                    break;
            }
            if (isRtl) {
                final int rd = (titleHasWidth ? mTitleMarginStart : 0) - collapsingMargins[1];
                right -= Math.max(0, rd);
                collapsingMargins[1] = Math.max(0, -rd);
                int titleRight = right;
                int subtitleRight = right;

                if (layoutTitle) {
                    final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutConfig();
                    final int titleLeft = titleRight - mTitleTextView.getEstimatedWidth();
                    final int titleBottom = titleTop + mTitleTextView.getEstimatedHeight();
                    mTitleTextView.arrange(titleLeft, titleTop, titleRight - titleLeft, titleBottom - titleTop);
                    titleRight = titleLeft - mTitleMarginEnd;
                    titleTop = titleBottom + lp.getMarginBottom();
                }
                if (layoutSubtitle) {
                    final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutConfig();
                    titleTop += lp.getMarginTop();
                    final int subtitleLeft = subtitleRight - mSubtitleTextView.getEstimatedWidth();
                    final int subtitleBottom = titleTop + mSubtitleTextView.getEstimatedHeight();
                    mSubtitleTextView.arrange(subtitleLeft, titleTop, subtitleRight - subtitleLeft, subtitleBottom - titleTop);
                    subtitleRight = subtitleRight - mTitleMarginEnd;
                    titleTop = subtitleBottom + lp.getMarginBottom();
                }
                if (titleHasWidth) {
                    right = Math.min(titleRight, subtitleRight);
                }
            } else {
                final int ld = (titleHasWidth ? mTitleMarginStart : 0) - collapsingMargins[0];
                left += Math.max(0, ld);
                collapsingMargins[0] = Math.max(0, -ld);
                int titleLeft = left;
                int subtitleLeft = left;

                if (layoutTitle) {
                    final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutConfig();
                    final int titleRight = titleLeft + mTitleTextView.getEstimatedWidth();
                    final int titleBottom = titleTop + mTitleTextView.getEstimatedHeight();
                    mTitleTextView.arrange(titleLeft, titleTop, titleRight - titleLeft, titleBottom - titleTop);
                    titleLeft = titleRight + mTitleMarginEnd;
                    titleTop = titleBottom + lp.getMarginBottom();
                }
                if (layoutSubtitle) {
                    final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutConfig();
                    titleTop += lp.getMarginTop();
                    final int subtitleRight = subtitleLeft + mSubtitleTextView.getEstimatedWidth();
                    final int subtitleBottom = titleTop + mSubtitleTextView.getEstimatedHeight();
                    mSubtitleTextView.arrange(subtitleLeft, titleTop, subtitleRight - subtitleLeft, subtitleBottom - titleTop);
                    subtitleLeft = subtitleRight + mTitleMarginEnd;
                    titleTop = subtitleBottom + lp.getMarginBottom();
                }
                if (titleHasWidth) {
                    left = Math.max(titleLeft, subtitleLeft);
                }
            }
        }

        // Get all remaining children sorted for layout. This is all prepared
        // such that absolute layout direction can be used below.

        addCustomViewsWithGravity(mTempViews, Gravity.LEFT);
        final int leftViewsCount = mTempViews.size();
        for (int i = 0; i < leftViewsCount; i++) {
            left = layoutChildLeft(mTempViews.get(i), left, collapsingMargins,
                    alignmentHeight);
        }

        addCustomViewsWithGravity(mTempViews, Gravity.RIGHT);
        final int rightViewsCount = mTempViews.size();
        for (int i = 0; i < rightViewsCount; i++) {
            right = layoutChildRight(mTempViews.get(i), right, collapsingMargins,
                    alignmentHeight);
        }

        // Centered views try to center with respect to the whole bar, but views pinned
        // to the left or right can push the mass of centered views to one side or the other.
        addCustomViewsWithGravity(mTempViews, Gravity.CENTER_HORIZONTAL);
        final int centerViewsWidth = getViewListMeasuredWidth(mTempViews, collapsingMargins);
        final int parentCenter = paddingLeft + (width - paddingLeft - paddingRight) / 2;
        final int halfCenterViewsWidth = centerViewsWidth / 2;
        int centerLeft = parentCenter - halfCenterViewsWidth;
        final int centerRight = centerLeft + centerViewsWidth;
        if (centerLeft < left) {
            centerLeft = left;
        } else if (centerRight > right) {
            centerLeft -= centerRight - right;
        }

        final int centerViewsCount = mTempViews.size();
        for (int i = 0; i < centerViewsCount; i++) {
            centerLeft = layoutChildLeft(mTempViews.get(i), centerLeft, collapsingMargins,
                    alignmentHeight);
        }
        mTempViews.clear();

        return true;
    }

    private int getViewListMeasuredWidth(List<Component> views, int[] collapsingMargins) {
        int collapseLeft = collapsingMargins[0];
        int collapseRight = collapsingMargins[1];
        int width = 0;
        final int count = views.size();
        for (int i = 0; i < count; i++) {
            final Component v = views.get(i);
            final LayoutParams lp = (LayoutParams) v.getLayoutConfig();
            final int l = lp.getMarginLeft() - collapseLeft;
            final int r = lp.getMarginRight() - collapseRight;
            final int leftMargin = Math.max(0, l);
            final int rightMargin = Math.max(0, r);
            collapseLeft = Math.max(0, -l);
            collapseRight = Math.max(0, -r);
            width += leftMargin + v.getEstimatedWidth() + rightMargin;
        }
        return width;
    }

    private int layoutChildLeft(Component child, int left, int[] collapsingMargins,
                                int alignmentHeight) {
        final LayoutParams lp = (LayoutParams) child.getLayoutConfig();
        final int l = lp.getMarginLeft() - collapsingMargins[0];
        left += Math.max(0, l);
        collapsingMargins[0] = Math.max(0, -l);
        final int top = getChildTop(child, alignmentHeight);
        final int childWidth = child.getEstimatedWidth();
        child.arrange(left, top, childWidth, child.getEstimatedHeight());
        left += childWidth + lp.getMarginRight();
        return left;
    }

    private int layoutChildRight(Component child, int right, int[] collapsingMargins,
                                 int alignmentHeight) {
        final LayoutParams lp = (LayoutParams) child.getLayoutConfig();
        final int r = lp.getMarginRight() - collapsingMargins[1];
        right -= Math.max(0, r);
        collapsingMargins[1] = Math.max(0, -r);
        final int top = getChildTop(child, alignmentHeight);
        final int childWidth = child.getEstimatedWidth();
        child.arrange(right - childWidth, top, childWidth, child.getEstimatedHeight());
        right -= childWidth + lp.getMarginLeft();
        return right;
    }

    private int getChildTop(Component child, int alignmentHeight) {
        int topAppend = mStatusBarHeight / 2;
        final LayoutParams lp = (LayoutParams) child.getLayoutConfig();
        final int childHeight = child.getEstimatedHeight();
        final int alignmentOffset = alignmentHeight > 0 ? (childHeight - alignmentHeight) / 2 : 0;
        switch (getChildVerticalGravity(lp.gravity)) {
            case Gravity.TOP:
                return getPaddingTop() - alignmentOffset + mStatusBarHeight;

            case Gravity.BOTTOM:
                return getHeight() - getPaddingBottom() - childHeight
                        - lp.getMarginBottom() - alignmentOffset - mStatusBarHeight;

            default:
            case Gravity.CENTER_VERTICAL:
                final int paddingTop = getPaddingTop();
                final int paddingBottom = getPaddingBottom();
                final int height = getHeight();
                final int space = height - paddingTop - paddingBottom;
                int spaceAbove = (space - childHeight) / 2;
                if (spaceAbove < lp.getMarginTop()) {
                    spaceAbove = lp.getMarginTop();
                } else {
                    final int spaceBelow = height - paddingBottom - childHeight -
                            spaceAbove - paddingTop;
                    if (spaceBelow < lp.getMarginBottom()) {
                        spaceAbove = Math.max(0, spaceAbove - (lp.getMarginBottom() - spaceBelow));
                    }
                }
                return paddingTop + spaceAbove + topAppend;
        }
    }

    private int getChildVerticalGravity(int gravity) {
        final int vgrav = gravity & Gravity.VERTICAL_GRAVITY_MASK;
        switch (vgrav) {
            case Gravity.TOP:
            case Gravity.BOTTOM:
            case Gravity.CENTER_VERTICAL:
                return vgrav;
            default:
                return mGravity & Gravity.VERTICAL_GRAVITY_MASK;
        }
    }

    /**
     * Prepare a list of non-SYSTEM child views. If the layout direction is RTL
     * this will be in reverse child order.
     *
     * @param views   List to populate. It will be cleared before use.
     * @param gravity Horizontal gravity to match against
     */
    private void addCustomViewsWithGravity(List<Component> views, int gravity) {
        final boolean isRtl = getLayoutDirection() == LayoutDirection.RTL;
        final int childCount = getChildCount();
        final int absGrav = Gravity.getAbsoluteGravity(gravity,
                getLayoutDirection());

        views.clear();

        if (isRtl) {
            for (int i = childCount - 1; i >= 0; i--) {
                final Component child = getComponentAt(i);
                final LayoutParams lp = (LayoutParams) child.getLayoutConfig();
                if (lp.mViewType == LayoutParams.CUSTOM && shouldLayout(child) &&
                        getChildHorizontalGravity(lp.gravity) == absGrav) {
                    views.add(child);
                }
            }
        } else {
            for (int i = 0; i < childCount; i++) {
                final Component child = getComponentAt(i);
                final LayoutParams lp = (LayoutParams) child.getLayoutConfig();
                if (lp.mViewType == LayoutParams.CUSTOM && shouldLayout(child) &&
                        getChildHorizontalGravity(lp.gravity) == absGrav) {
                    views.add(child);
                }
            }
        }
    }

    private int getChildHorizontalGravity(int gravity) {
        final LayoutDirection ld = getLayoutDirection();
        final int absGrav = Gravity.getAbsoluteGravity(gravity, ld);
        final int hGrav = absGrav & Gravity.HORIZONTAL_GRAVITY_MASK;
        switch (hGrav) {
            case Gravity.LEFT:
            case Gravity.RIGHT:
            case Gravity.CENTER_HORIZONTAL:
                return hGrav;
            default:
                return ld == LayoutDirection.RTL ? Gravity.RIGHT : Gravity.LEFT;
        }
    }

    private boolean shouldLayout(Component view) {
        return view != null && view.getComponentParent() == this && view.getVisibility() != HIDE;
    }

    private int getHorizontalMargins(Component v) {
        final LayoutConfig mlp = v.getLayoutConfig();
        return mlp.getMarginLeft() + mlp.getMarginRight();
    }

    private int getVerticalMargins(Component v) {
        final LayoutConfig mlp = v.getLayoutConfig();
        return mlp.getMarginTop() + mlp.getMarginBottom();
    }

//    @Override
//    public LayoutParams generateLayoutParams(AttributeSet attrs) {
//        return new LayoutParams(getContext(), attrs);
//    }
//
//    @Override
//    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
//        if (p instanceof LayoutParams) {
//            return new LayoutParams((LayoutParams) p);
//        } else if (p instanceof ActionBar.LayoutParams) {
//            return new LayoutParams((ActionBar.LayoutParams) p);
//        } else if (p instanceof MarginLayoutParams) {
//            return new LayoutParams((MarginLayoutParams) p);
//        } else {
//            return new LayoutParams(p);
//        }
//    }

    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.MATCH_CONTENT, LayoutParams.MATCH_CONTENT);
    }

    @Override
    public LayoutParams createLayoutConfig(Context context, AttrSet attrSet) {
        return new LayoutParams(context, attrSet);
    }

    @Override
    public ComponentContainer.LayoutConfig verifyLayoutConfig(ComponentContainer.LayoutConfig config) {
        if (config instanceof LayoutParams) return config;
        return new LayoutParams(config);
    }

    protected boolean checkLayoutParams(LayoutConfig p) {
        return p instanceof LayoutParams;
    }

    private static boolean isCustomView(Component child) {
        return ((LayoutParams) child.getLayoutConfig()).mViewType == LayoutParams.CUSTOM;
    }

//    /** @hide */
//    @RestrictTo(LIBRARY_GROUP)
//    public DecorToolbar getWrapper() {
//        if (mWrapper == null) {
//            mWrapper = new ToolbarWidgetWrapper(this, true);
//        }
//        return mWrapper;
//    }

    void removeChildrenForExpandedActionView() {
        final int childCount = getChildCount();
        // Go backwards since we're removing from the list
        for (int i = childCount - 1; i >= 0; i--) {
            final Component child = getComponentAt(i);
            final LayoutParams lp = (LayoutParams) child.getLayoutConfig();
            if (lp.mViewType != LayoutParams.EXPANDED) { //  && child != mMenuView
                removeComponentAt(i);
                mHiddenViews.add(child);
            }
        }
    }

    void addChildrenForExpandedActionView() {
        final int count = mHiddenViews.size();
        // Re-add in reverse order since we removed in reverse order
        for (int i = count - 1; i >= 0; i--) {
            addComponent(mHiddenViews.get(i));
        }
        mHiddenViews.clear();
    }

    private boolean isChildOrHidden(Component child) {
        return child.getComponentParent() == this || mHiddenViews.contains(child);
    }

    /**
     * Force the toolbar to collapse to zero-height during measurement if
     * it could be considered "empty" (no visible elements with nonzero measured size)
     *
     * @hide
     */
    public void setCollapsible(boolean collapsible) {
        mCollapsible = collapsible;
        postLayout();
    }

//    /**
//     * Must be called before the menu is accessed
//     * @hide
//     */
//    @RestrictTo(LIBRARY_GROUP)
//    public void setMenuCallbacks(MenuPresenter.Callback pcb, MenuBuilder.Callback mcb) {
//        mActionMenuPresenterCallback = pcb;
//        mMenuBuilderCallback = mcb;
//        if (mMenuView != null) {
//            mMenuView.setMenuCallbacks(pcb, mcb);
//        }
//    }

    private void ensureContentInsets() {
        if (mContentInsets == null) {
            mContentInsets = new RtlSpacingHelper();
        }
    }

//    /**
//     * Interface responsible for receiving menu item click events if the items themselves
//     * do not have individual item click listeners.
//     */
//    public interface OnMenuItemClickListener {
//        /**
//         * This method will be invoked when a menu item is clicked if the item itself did
//         * not already handle the event.
//         *
//         * @param item {@link MenuItem} that was clicked
//         * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
//         */
//        public boolean onMenuItemClick(MenuItem item);
//    }

    public static int resolveSize(int size, int measureSpec) {
        final int specMode = EstimateSpec.getMode(measureSpec);
        final int specSize = EstimateSpec.getSize(measureSpec);
        final int result;
        switch (specMode) {
            case EstimateSpec.NOT_EXCEED:
                if (specSize < size) {
                    result = specSize;
                } else {
                    result = size;
                }
                break;
            case EstimateSpec.PRECISE:
                result = specSize;
                break;
            case EstimateSpec.UNCONSTRAINT:
            default:
                result = size;
        }
        return result;
    }

    /**
     * Layout information for child views of Toolbars.
     *
     * <p>Toolbar.LayoutParams extends ActionBar.LayoutParams for compatibility with existing
     * ActionBar API.
     * for more info on how to use a Toolbar as your Activity's ActionBar.</p>
     */
    public static class LayoutParams extends LayoutConfig {
        static final int CUSTOM = 0;
        static final int SYSTEM = 1;
        static final int EXPANDED = 2;

        int mViewType = CUSTOM;
        public int gravity = Gravity.NO_GRAVITY;

        public LayoutParams(Context c, AttrSet attrs) {
            super(c, attrs);

            gravity = Gravity.convert(attrs.getAttr("layout_gravity").map(Attr::getStringValue).orElse(""));
        }

        public LayoutParams(int width, int height) {
            super(width, height);
            this.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
        }

        public LayoutParams(int width, int height, int gravity) {
            super(width, height);
            this.gravity = gravity;
        }

        public LayoutParams(int gravity) {
            this(MATCH_CONTENT, MATCH_PARENT, gravity);
        }

        public LayoutParams(LayoutParams source) {
            super(source);

            mViewType = source.mViewType;
        }

        public LayoutParams(ComponentContainer.LayoutConfig source) {
            super(source);
        }
    }

//    public static class SavedState extends AbsSavedState {
//        int expandedMenuItemId;
//        boolean isOverflowOpen;
//
//        public SavedState(Parcel source) {
//            this(source, null);
//        }
//
//        public SavedState(Parcel source, ClassLoader loader) {
//            super(source, loader);
//            expandedMenuItemId = source.readInt();
//            isOverflowOpen = source.readInt() != 0;
//        }
//
//        public SavedState(Parcelable superState) {
//            super(superState);
//        }
//
//        @Override
//        public void writeToParcel(Parcel out, int flags) {
//            super.writeToParcel(out, flags);
//            out.writeInt(expandedMenuItemId);
//            out.writeInt(isOverflowOpen ? 1 : 0);
//        }
//
//        public static final Creator<SavedState> CREATOR = ParcelableCompat.newCreator(
//                new ParcelableCompatCreatorCallbacks<SavedState>() {
//                    @Override
//                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
//                        return new SavedState(in, loader);
//                    }
//
//                    @Override
//                    public SavedState[] newArray(int size) {
//                        return new SavedState[size];
//                    }
//                });
//    }

//    private class ExpandedActionViewMenuPresenter implements MenuPresenter {
//        MenuBuilder mMenu;
//        MenuItemImpl mCurrentExpandedItem;
//
//        ExpandedActionViewMenuPresenter() {
//        }
//
//        @Override
//        public void initForMenu(Context context, MenuBuilder menu) {
//            // Clear the expanded action view when menus change.
//            if (mMenu != null && mCurrentExpandedItem != null) {
//                mMenu.collapseItemActionView(mCurrentExpandedItem);
//            }
//            mMenu = menu;
//        }
//
//        @Override
//        public MenuView getMenuView(ViewGroup root) {
//            return null;
//        }
//
//        @Override
//        public void updateMenuView(boolean cleared) {
//            // Make sure the expanded item we have is still there.
//            if (mCurrentExpandedItem != null) {
//                boolean found = false;
//
//                if (mMenu != null) {
//                    final int count = mMenu.size();
//                    for (int i = 0; i < count; i++) {
//                        final MenuItem item = mMenu.getItem(i);
//                        if (item == mCurrentExpandedItem) {
//                            found = true;
//                            break;
//                        }
//                    }
//                }
//
//                if (!found) {
//                    // The item we had expanded disappeared. Collapse.
//                    collapseItemActionView(mMenu, mCurrentExpandedItem);
//                }
//            }
//        }
//
//        @Override
//        public void setCallback(Callback cb) {
//        }
//
//        @Override
//        public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
//            return false;
//        }
//
//        @Override
//        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
//        }
//
//        @Override
//        public boolean flagActionItems() {
//            return false;
//        }
//
//        @Override
//        public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
//            ensureCollapseButtonView();
//            if (mCollapseButtonView.getParent() != Toolbar.this) {
//                addView(mCollapseButtonView);
//            }
//            mExpandedActionView = item.getActionView();
//            mCurrentExpandedItem = item;
//            if (mExpandedActionView.getParent() != Toolbar.this) {
//                final LayoutParams lp = generateDefaultLayoutParams();
//                lp.gravity = GravityCompat.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
//                lp.mViewType = LayoutParams.EXPANDED;
//                mExpandedActionView.setLayoutParams(lp);
//                addView(mExpandedActionView);
//            }
//
//            removeChildrenForExpandedActionView();
//            requestLayout();
//            item.setActionViewExpanded(true);
//
//            if (mExpandedActionView instanceof CollapsibleActionView) {
//                ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded();
//            }
//
//            return true;
//        }
//
//        @Override
//        public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
//            // Do this before detaching the actionview from the hierarchy, in case
//            // it needs to dismiss the soft keyboard, etc.
//            if (mExpandedActionView instanceof CollapsibleActionView) {
//                ((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed();
//            }
//
//            removeView(mExpandedActionView);
//            removeView(mCollapseButtonView);
//            mExpandedActionView = null;
//
//            addChildrenForExpandedActionView();
//            mCurrentExpandedItem = null;
//            requestLayout();
//            item.setActionViewExpanded(false);
//
//            return true;
//        }
//
//        @Override
//        public int getId() {
//            return 0;
//        }
//
//        @Override
//        public Parcelable onSaveInstanceState() {
//            return null;
//        }
//
//        @Override
//        public void onRestoreInstanceState(Parcelable state) {
//        }
//    }
}
